#include "bsp_spi.h"
#if (CONFIG_OS_ENABLE == 1)
#include "os_sal.h"
#endif





/* BSP-SPI4 */

/**
 * SPI3_SCK  : PC10 - AF6
 * SPI3_MOSI : PC12 - AF6
 * 
 * SPI4_SCK  : PE12 - AF5
 * SPI4_MISO : PE13 - AF5
 * SPI4_MOSI : PE14 - AF5
 */


/* static var */
static SPI_HandleTypeDef spi3_handle;
static DMA_HandleTypeDef spi3_dma_tx_handle;
static uint8_t flag_spi3_init = 0;

static SPI_HandleTypeDef spi4_handle = { 0 };
static uint8_t flag_spi4_init = 0;

#if (CONFIG_OS_ENABLE == 1)
static os_sem_handle_t spi3_dma_sem = NULL;
static os_mutex_handle_t spi3_mutex = NULL;
static os_mutex_handle_t spi4_mutex = NULL;
#else
uint8_t spi3_dma_flag = 0;
#endif


/* static func */


void SPI3_IRQHandler(void)
{
    HAL_SPI_IRQHandler(&spi3_handle);
}

void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
    if (hspi->Instance == SPI3) 
    {
        // printf("B\r\n");
    #if (CONFIG_OS_ENABLE == 1)
        os_sem_release(spi3_dma_sem);   // 释放信号量
    #else
        spi3_dma_flag = 0;
    #endif
    }
}

void DMA2_Stream3_IRQHandler(void)
{
    HAL_DMA_IRQHandler(spi3_handle.hdmatx);
}

static void bsp_spi3_gpio_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    __HAL_RCC_GPIOC_CLK_ENABLE();

    /* SPI3_SCK : PC10-AF6 */
    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    /* SPI3_MOSI : PC12-AF6 */
    GPIO_InitStruct.Pin = GPIO_PIN_12;
    GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}

static void bsp_spi3_param_init(void)
{
    __HAL_RCC_SPI3_CLK_ENABLE();

    /* SPI3 */
    spi3_handle.Instance = SPI3;
    spi3_handle.Init.Mode = SPI_MODE_MASTER;
    spi3_handle.Init.Direction = SPI_DIRECTION_2LINES_TXONLY;
    spi3_handle.Init.DataSize = SPI_DATASIZE_8BIT;
    spi3_handle.Init.CLKPolarity = SPI_POLARITY_HIGH;   //空闲状态高电平
    spi3_handle.Init.CLKPhase = SPI_PHASE_2EDGE;    //第二个跳变沿（上升或下降）数据被采样
    spi3_handle.Init.NSS = SPI_NSS_SOFT;
    spi3_handle.Init.NSSPMode = SPI_NSS_PULSE_DISABLED;
    spi3_handle.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;
    spi3_handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; //分频值
    spi3_handle.Init.FirstBit = SPI_FIRSTBIT_MSB;
    spi3_handle.Init.TIMode = SPI_TIMODE_DISABLE;
    spi3_handle.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
    spi3_handle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    spi3_handle.Init.CRCPolynomial = 7;
    spi3_handle.Init.IOSwap = SPI_IO_SWAP_DISABLE;
    HAL_SPI_Init(&spi3_handle);

    /* 配置DMA和NVIC */
	#if 1
	{
		/* Enable DMA clock */
		__HAL_RCC_DMA2_CLK_ENABLE();
		
		/* Configure the DMA handler for Transmission process */
		spi3_dma_tx_handle.Instance                 = DMA2_Stream3; // 
		spi3_dma_tx_handle.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;
		spi3_dma_tx_handle.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
		spi3_dma_tx_handle.Init.MemBurst            = DMA_MBURST_SINGLE;	// 存储器突发单次传输
		spi3_dma_tx_handle.Init.PeriphBurst         = DMA_PBURST_SINGLE;	// 外设突发单次传输
		spi3_dma_tx_handle.Init.Request             = DMA_REQUEST_SPI3_TX;  // 
		spi3_dma_tx_handle.Init.Direction           = DMA_MEMORY_TO_PERIPH;
		spi3_dma_tx_handle.Init.PeriphInc           = DMA_PINC_DISABLE;
		spi3_dma_tx_handle.Init.MemInc              = DMA_MINC_ENABLE;
		spi3_dma_tx_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
		spi3_dma_tx_handle.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
		spi3_dma_tx_handle.Init.Mode                = DMA_NORMAL;
		spi3_dma_tx_handle.Init.Priority            = DMA_PRIORITY_MEDIUM;
		HAL_DMA_Init(&spi3_dma_tx_handle);
		__HAL_LINKDMA(&spi3_handle, hdmatx, spi3_dma_tx_handle);	 /* Associate the initialized DMA handle to the the SPI handle */

		/* NVIC configuration for DMA transfer complete interrupt (SPI3_TX) */
		HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 8, 0);
		HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);
		
		/* NVIC configuration for SPI transfer complete interrupt (SPI3) */
		HAL_NVIC_SetPriority(SPI3_IRQn, 7, 0);
		HAL_NVIC_EnableIRQ(SPI3_IRQn);
	}
	#endif
}

/* export func */

/**
 * @brief SPI3初始化,tx only
 * 
 */
void bsp_spi3_init(void)
{
	if (flag_spi3_init) return ;
	
    bsp_spi3_gpio_init();
    bsp_spi3_param_init();

    __HAL_SPI_ENABLE(&spi3_handle);

#if (CONFIG_OS_ENABLE == 1)
    spi3_dma_sem = os_sem_binary_create();  // 创建DMA二值信号量
    spi3_mutex = os_mutex_create();
#endif

    flag_spi3_init = 1;
}

/**
 * @brief 获取SPI3句柄
 * 
 * @return SPI_HandleTypeDef* 
 */
SPI_HandleTypeDef *bsp_spi3_get_handle(void)
{
    return &spi3_handle;
}

/**
 * @brief SPI3互斥锁锁定
 * 
 */
void bsp_spi3_lock(void)
{
#if (CONFIG_OS_ENABLE == 1)
    os_mutex_take(spi3_mutex, OS_WAIT_MAX);
#endif
}

/**
 * @brief SPI3互斥锁解锁
 * 
 */
void bsp_spi3_unlock(void)
{
#if (CONFIG_OS_ENABLE == 1)
    os_mutex_release(spi3_mutex);
#endif
}

/**
 * @brief SPI3设置速度
 * 
 * @param speed 
 */
void bsp_spi3_set_speed(uint32_t speed)
{
    assert_param(IS_SPI_BAUDRATE_PRESCALER(speed));
    // __HAL_SPI_DISABLE(&spi3_handle);            //关闭SPI
    spi3_handle.Instance->CFG1&=~(0X7<<28);     //位30-28清零，用来设置分频系数
    spi3_handle.Instance->CFG1|=speed;  //设置SPI速度
    // __HAL_SPI_ENABLE(&spi3_handle); //使能SPI
}

/**
 * @brief SPI3写入一字节
 * 
 * @param data 
 * @return uint8_t 
 */
uint8_t bsp_spi3_write_byte(uint8_t data)
{
#if 0
    return HAL_SPI_Transmit(&spi3_handle, &data, 1, 1000);
#else
    // SPI3->CFG1 = SPI_BAUDRATEPRESCALER_4 | 7;
    SPI3->CR1 = SPI_CR1_SSI;
    SPI3->CR2 = 1;
    SPI3->CR1 = SPI_CR1_SPE | SPI_CR1_SSI;
    SPI3->CR1 = SPI_CR1_SPE | SPI_CR1_SSI | SPI_CR1_CSTART;

    while ((SPI3->SR & SPI_FLAG_TXE) == 0);

    *((__IO uint8_t *)&SPI3->TXDR) = data;
	
    while ((SPI3->SR & SPI_SR_TXC) == 0);
	
    SPI3->IFCR = SPI_IFCR_EOTC | SPI_IFCR_TXTFC;
	SPI3->CR1 &= ~(SPI_CR1_SPE);

    return 0;
#endif
}

/**
 * @brief SPI3写入指定长度缓存
 * 
 * @param data 缓存地址
 * @param size 缓存大小
 * @return uint8_t 
 */
uint8_t bsp_spi3_write_buff(uint8_t *data, uint32_t size)
{
#if 0
    uint16_t tmp;
    while (size)
    {
        if (size > 0xFFFFU) tmp = 0xFFFFU;
        else tmp = size;

        HAL_SPI_Transmit(&spi3_handle, data, tmp, HAL_MAX_DELAY);

        size -= tmp;
        if (size) data += tmp;
    }
#else 
    uint16_t tmp;

    while (size)
    {
        if (size > 0xFFFFU) tmp = 0xFFFFU;
        else tmp = size;
        size -= tmp;

        SPI3->CR2 = tmp;    // CR2 一次最大发送数16bits,超出部分分批发送
        SPI3->CR1 = SPI_CR1_SSI;
        SPI3->CR1 = SPI_CR1_SPE | SPI_CR1_SSI;
        SPI3->CR1 = SPI_CR1_SPE | SPI_CR1_SSI | SPI_CR1_CSTART;

        while (tmp--)
        {
            while ((SPI3->SR & SPI_FLAG_TXE) == 0);
            *((__IO uint8_t *)&SPI3->TXDR) = *data;
            data++;
        }

        while ((SPI3->SR & SPI_SR_TXC) == 0);
        
        SPI3->IFCR = SPI_IFCR_EOTC | SPI_IFCR_TXTFC;
    	SPI3->CR1 &= ~(SPI_CR1_SPE);
    }
    
#endif
    return 0;
}

/**
 * @brief SPI3写入指定长度缓存，DMA方式
 * 
 * @param data 写入缓存
 * @param size 缓存大小
 * @return uint8_t 
 */
uint8_t bsp_spi3_write_buff_dma(uint8_t *data, uint32_t size)
{
    uint16_t tmp;
    uint8_t sta;

    // SPI3->CFG1 = SPI_BAUDRATEPRESCALER_2 | 7;   // 刷屏，倍速 (2分频，100M)

    while (size)
    {
    #if (CONFIG_OS_ENABLE == 1)
    #else
        spi3_dma_flag = 0;
    #endif
        if (size > 0xFFFFU) tmp = 0xFFFFU;
        else tmp = size;

        sta = HAL_SPI_Transmit_DMA(&spi3_handle, data, tmp);
        if (sta != HAL_OK)
        {
            printf("tran err %d\r\n", sta);
        }

        size -= tmp;
        if (size) data += tmp;

        // wait dma finsh
    #if (CONFIG_OS_ENABLE == 1)
        sta = os_sem_take(spi3_dma_sem, 2000);
        if (sta != OS_STA_SUCCESS)
        {
            printf("spi3 wait timeout\r\n");
        }
    #else
        while(spi3_dma_flag == 1)
        {
        }
    #endif
    }

    // SPI3->CFG1 = SPI_BAUDRATEPRESCALER_4 | 7;   // 降速

    return 0;
}

/* SPI4 */

/**
 * @brief SPI4初始化
 * 
 */
void bsp_spi4_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    if (flag_spi4_init) return;

    __HAL_RCC_GPIOE_CLK_ENABLE();
    __HAL_RCC_SPI4_CLK_ENABLE();

    /* SPI4_SCK : PE12-AF5 */
    GPIO_InitStruct.Pin = GPIO_PIN_12;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI4;
    HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);

    /* SPI4_MISO : PE13-AF5 */
    GPIO_InitStruct.Pin = GPIO_PIN_13;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI4;
    HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);

    /* SPI4_MOSI : PE14-AF5 */
    GPIO_InitStruct.Pin = GPIO_PIN_14;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI4;
    HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);

    /* SPI4 */
    spi4_handle.Instance = SPI4;
    spi4_handle.Init.Mode = SPI_MODE_MASTER;
    spi4_handle.Init.Direction = SPI_DIRECTION_2LINES;
    spi4_handle.Init.DataSize = SPI_DATASIZE_8BIT;
    spi4_handle.Init.CLKPolarity = SPI_POLARITY_HIGH;   //空闲状态高电平
    spi4_handle.Init.CLKPhase = SPI_PHASE_2EDGE;    //第二个跳变沿（上升或下降）数据被采样
    spi4_handle.Init.NSS = SPI_NSS_SOFT;
    spi4_handle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
    spi4_handle.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;
    spi4_handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256; //分频值,最高速
    spi4_handle.Init.FirstBit = SPI_FIRSTBIT_MSB;
    spi4_handle.Init.TIMode = SPI_TIMODE_DISABLE;
    spi4_handle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    spi4_handle.Init.CRCPolynomial = 7;
    spi4_handle.Init.IOSwap = SPI_IO_SWAP_DISABLE;
    spi4_handle.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
    spi4_handle.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
    HAL_SPI_Init(&spi4_handle);

    __HAL_SPI_ENABLE(&spi4_handle);
    bsp_spi4_read_write_byte(0xFF);

#if (CONFIG_OS_ENABLE == 1)
    spi4_mutex = os_mutex_create();
#endif

    flag_spi4_init = 1;
}

/**
 * @brief SPI4获取句柄
 * 
 * @return SPI_HandleTypeDef* 
 */
SPI_HandleTypeDef *bsp_spi4_get_handle(void)
{
    return &spi4_handle;
}

void bsp_spi4_lock(void)
{
#if (CONFIG_OS_ENABLE == 1)
    os_mutex_take(spi4_mutex, OS_WAIT_MAX);
#endif
}

void bsp_spi4_unlock(void)
{
#if (CONFIG_OS_ENABLE == 1)
    os_mutex_release(spi4_mutex);
#endif
}

/**
 * @brief SPI4设置速度
 * 
 * @param speed 
 */
void bsp_spi4_set_speed(uint32_t speed)
{
    assert_param(IS_SPI_BAUDRATE_PRESCALER(speed));
    __HAL_SPI_DISABLE(&spi4_handle);            //关闭SPI
    spi4_handle.Instance->CFG1&=~(0X7<<28);     //位30-28清零，用来设置分频系数
    spi4_handle.Instance->CFG1|=speed;  //设置SPI速度
    __HAL_SPI_ENABLE(&spi4_handle); //使能SPI
}


/**
 * @brief SPI4读写一字节
 * 
 * @param data 
 * @return uint8_t 
 */
uint8_t bsp_spi4_read_write_byte(uint8_t data)
{
    uint8_t val;
#if 0
    HAL_SPI_TransmitReceive(&spi4_handle, &data, &val, 1, 1000);
#else
    uint16_t retry = 0;

    SPI4->CR1 |= 1 << 0; // SPE=1,使能SPI2
    SPI4->CR1 |= 1 << 9; // CSTART=1,启动传输

    while ((SPI4->SR & 1 << 1) == 0) // 等待发送区空
    {
        retry++;
        if (retry > 0XFFFE) return 0;
    }
    *(volatile uint8_t *)&SPI4->TXDR = data; // 发送一个byte
    retry = 0;
    while ((SPI4->SR & 1 << 0) == 0) // 等待接收完一个byte
    {
        retry++;
        if (retry > 0XFFFE) return 0;
    }
    val = *(volatile uint8_t *)&SPI4->RXDR;

    SPI4->IFCR |= 3 << 3;   // EOTC和TXTFC置1,清除EOT和TXTFC位
    SPI4->CR1 &= ~(1 << 0); // SPE=0,关闭SPI2,会执行状态机复位/FIFO重置等操作

#endif
    return val; // 返回收到的数据
}

uint8_t bsp_spi4_write_buff(uint8_t *data, uint32_t size)
{
#if 0
    uint16_t tmp;
    while (size)
    {
        if (size > 0xFFFFU) tmp = 0xFFFFU;
        else tmp = size;

        HAL_SPI_Transmit(&spi4_handle, data, tmp, HAL_MAX_DELAY);

        size -= tmp;
        if (size) data += tmp;
    }
#else 
    uint16_t tmp;

    while (size)
    {
        if (size > 0xFFFFU) tmp = 0xFFFFU;
        else tmp = size;
        size -= tmp;

        SPI4->CR2 = tmp;    // CR2 一次最大发送数16bits,超出部分分批发送
        SPI4->CR1 = SPI_CR1_SSI;
        SPI4->CR1 = SPI_CR1_SPE | SPI_CR1_SSI;
        SPI4->CR1 = SPI_CR1_SPE | SPI_CR1_SSI | SPI_CR1_CSTART;

        while (tmp--)
        {
            while ((SPI4->SR & SPI_FLAG_TXE) == 0);
            *((__IO uint8_t *)&SPI4->TXDR) = *data;
            data++;
        }

        while ((SPI4->SR & SPI_SR_TXC) == 0);
        
        SPI4->IFCR = SPI_IFCR_EOTC | SPI_IFCR_TXTFC;
    	SPI4->CR1 &= ~(SPI_CR1_SPE);
    }
    
#endif
    return 0;
}

uint8_t bsp_spi4_read_buff(uint8_t *data, uint32_t size)
{
    uint16_t tmp;
    uint8_t ret = 0;

    while (size)
    {
        if (size > 0xFFFFU) tmp = 0xFFFFU;
        else tmp = size;

        ret |= HAL_SPI_Receive(&spi4_handle, data, tmp, HAL_MAX_DELAY);

        size -= tmp;
        if (size) data += tmp;
    }

    return ret;
}
